//Komissarov Denis
package MAINWIN;

import javax.swing.JPanel;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Insets;
import java.util.*;
import javax.swing.Box;
import javax.swing.InputVerifier;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.SwingConstants;
import javax.swing.border.EmptyBorder;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableModel;
import CalculationCore.CCPUBlackBox;
import Resources.CEnvironment;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

public class CRegistreForm extends JDialog {

	private static final long serialVersionUID = 5684971613818504535L;
	private ArrayList<JTextField> txtMem = new ArrayList<JTextField>();
	private ArrayList<JCheckBox> chkMem = new ArrayList<JCheckBox>();
	ArrayList<stackBean> stackBeans = new ArrayList<stackBean>();
	ArrayList<stackBean> pstackBeans = new ArrayList<stackBean>();
	TableModel stackModel = new stackTableModel(stackBeans);
	TableModel pstackModel = new pstackTableModel(pstackBeans);
	JTable stackTable = new JTable(stackModel);
	JTable pstackTable = new JTable(pstackModel);
	private CCPUBlackBox calc;
	private int canEdit = 0;
	private JTextField txtX0;
	JLabel lblX0;
	private boolean unCheck = false;

	public CRegistreForm(String title, final CCPUBlackBox calc) {
		addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent arg0) {
				setRegisters();
			}
		});

		this.calc = calc;
		setSize(551, 484);
		setLocationRelativeTo(null);
		setResizable(isMinimumSizeSet());
		setTitle(title);

		int rowCount = calc.getB3_34memory().getSize() + 2;

		// Registers
		JPanel panel_1 = new JPanel();
		getContentPane().add(panel_1, BorderLayout.CENTER);
		panel_1.setBorder(new EmptyBorder(20, 0, 25, 25));
		panel_1.setLayout(new GridLayout(rowCount, 3, 5, 5));

		JLabel lblMem = new JLabel(CEnvironment.RegistreRegMem);
		panel_1.add(Box.createRigidArea(new Dimension(0, 0)));
		panel_1.add(lblMem);
		panel_1.add(Box.createRigidArea(new Dimension(0, 0)));

		String tmpStr;

		for (int index = 0; index < calc.getB3_34memory().getSize(); index++) {

			switch (index) {
			case 10:
				tmpStr = "A";
				break;
			case 11:
				tmpStr = "B";
				break;
			case 12:
				tmpStr = "C";
				break;
			case 13:
				tmpStr = "D";
				break;
			case 14:
				tmpStr = "E";
				break;
			case 15:
				tmpStr = "F";
				break;
			default:
				tmpStr = String.valueOf(index);
				break;
			}
			JLabel lbl = new JLabel("M" + tmpStr + ":");
			lbl.setHorizontalAlignment(SwingConstants.RIGHT);
			panel_1.add(lbl);

			JTextField txt = new JTextField();
			txt.setEditable(false);
			txt.setInputVerifier(new InputVerifier() {
				public boolean verify(JComponent comp) {
					boolean returnValue = true;
					JTextField textField = (JTextField) comp;
					String content = textField.getText();
					if (content.length() != 0) {
						try {
							Double.parseDouble(textField.getText());
						} catch (NumberFormatException e) {
							getToolkit().beep();
							returnValue = false;
						}
					}
					return returnValue;
				}
			});
			txtMem.add(txt);
			panel_1.add(txt);

			JCheckBox chk = new JCheckBox();
			chk.setVisible(false);
			chkMem.add(chk);
			panel_1.add(chk);
		}

		// Clear register button
		JButton btnRegClear = new JButton(CEnvironment.RegistreClear);
		btnRegClear.setMargin(new Insets(2, 2, 2, 2));
		btnRegClear.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				calc.cleanupMemory();
				registreUpdate();
			}
		});
		panel_1.add(Box.createRigidArea(new Dimension(0, 0)));
		panel_1.add(btnRegClear);

		// Stack
		JPanel panel = new JPanel();
		getContentPane().add(panel, BorderLayout.EAST);
		panel.setPreferredSize(new Dimension(200, 400));
		panel.setBorder(new EmptyBorder(20, 0, 25, 25));
		panel.setLayout(null);

		JLabel lblStack = new JLabel(CEnvironment.RegistreStack);
		lblStack.setBounds(0, 70, 175, 14);
		lblStack.setHorizontalAlignment(SwingConstants.LEFT);
		panel.add(lblStack);

		stackTable.getColumnModel().getColumn(0).setPreferredWidth(10);
		JScrollPane scrollPane = new JScrollPane(stackTable);
		scrollPane.setBounds(0, 95, 175, 99);
		panel.add(scrollPane);

		// Clear stack button
		JButton btnStackClear = new JButton(CEnvironment.RegistreClear);
		btnStackClear.setBounds(0, 205, 175, 21);
		btnStackClear.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				calc.cleanupStack();
				registreUpdate();
				CMainForm.LEDout(" 0.");
			}
		});
		panel.add(btnStackClear);

		// Program stack

		JLabel lblStackP = new JLabel(CEnvironment.RegistreStack2);
		lblStackP.setBounds(0, 237, 175, 14);
		lblStackP.setHorizontalAlignment(SwingConstants.LEFT);
		panel.add(lblStackP);

		pstackTable.getColumnModel().getColumn(0).setPreferredWidth(10);
		JScrollPane scrollPane1 = new JScrollPane(pstackTable);
		scrollPane1.setBounds(0, 262, 175, 99);
		panel.add(scrollPane1);

		// Clear stack button
		JButton btnStackPClear = new JButton(CEnvironment.RegistreClear);
		btnStackPClear.setBounds(0, 370, 175, 21);
		btnStackPClear.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				calc.cleanupReturnStack();
				registreUpdate();
			}
		});
		panel.add(btnStackPClear);

		JButton btnNewButton = new JButton(CEnvironment.RegistreClose);
		btnNewButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				setRegisters();
				setVisible(false);
			}
		});
		btnNewButton.setBounds(0, 402, 175, 30);
		panel.add(btnNewButton);
		
		lblX0 = new JLabel(CEnvironment.RegistreX0);
		lblX0.setBounds(0, 47, 46, 14);
		panel.add(lblX0);
		
		txtX0 = new JTextField();
		txtX0.setEditable(false);
		txtX0.setBounds(56, 44, 119, 20);
		txtX0.setInputVerifier(new InputVerifier() {
			public boolean verify(JComponent comp) {
				boolean returnValue = true;
				JTextField textField = (JTextField) comp;
				String content = textField.getText();
				if (content.length() != 0) {
					try {
						Double.parseDouble(textField.getText());
					} catch (NumberFormatException e) {
						getToolkit().beep();
						returnValue = false;
					}
				}
				return returnValue;
			}
		});
		panel.add(txtX0);
	}

	synchronized public void registreUpdate() {

		try {
			String[] strStack0 = calc.getStackToFrame();
			String[] strStack1 = calc.getReturnStackToFrame();
			String[] strMem = calc.getMemoryToFrame();

			txtX0.setText(String.valueOf(calc.getB3_34stack().getAuxX().getdFullNumber()));
			
			stackBeans.clear();

			for (int index = 0; index < calc.getB3_34stack().getSize(); index++) {
				if (strStack0[index].matches("NAN")) {
					strStack0[index] = "+0.";
					if (canEdit > 0) {
						stackBeans.add(new stackBean("X" + Integer.valueOf(index + 1),
								strStack0[index], false));
					} else {
						stackBeans.add(new stackBean("X" + Integer.valueOf(index + 1),
								strStack0[index], true));
					}
				} else {
					if (canEdit > 0) {
						stackBeans.add(new stackBean("X" + Integer.valueOf(index + 1),
								strStack0[index], !unCheck));
					} else {
						stackBeans.add(new stackBean("X" + Integer.valueOf(index + 1),
								strStack0[index], false));
					}
				}
			}

			if (stackTable.getColumnModel().getColumnCount() > 2) {
				if (canEdit < 2) {
					stackTable.getColumnModel().removeColumn(
							stackTable.getColumnModel().getColumn(2));
				} else {
					stackTable.getColumnModel().getColumn(2).setMinWidth(20);
					stackTable.getColumnModel().getColumn(2).setMaxWidth(20);
					stackTable.getColumnModel().getColumn(2)
							.setPreferredWidth(20);
				}
			}
			stackTable.revalidate();
			stackTable.repaint();

			pstackBeans.clear();
			for (int index = 0; index < calc.getB3_34returnstack().getSize(); index++) {
				if (strStack1[index].matches(String.valueOf(Integer.MAX_VALUE))) {
					strStack1[index] = "0";
					if (canEdit > 0) {
						pstackBeans.add(new stackBean("R" + index,
								strStack1[index], false));
					} else {
						pstackBeans.add(new stackBean("R" + index,
								strStack1[index], true));
					}
				} else {
					if (canEdit > 0) {
						pstackBeans.add(new stackBean("R" + index,
								strStack1[index], !unCheck));
					} else {
						pstackBeans.add(new stackBean("R" + index,
								strStack1[index], false));
					}
				}
			}

			if (pstackTable.getColumnModel().getColumnCount() > 2) {
				if (canEdit < 2) {
					pstackTable.getColumnModel().removeColumn(
							pstackTable.getColumnModel().getColumn(2));
				} else {
					pstackTable.getColumnModel().getColumn(2).setMinWidth(20);
					pstackTable.getColumnModel().getColumn(2).setMaxWidth(20);
					pstackTable.getColumnModel().getColumn(2)
							.setPreferredWidth(20);
				}
			}
			pstackTable.revalidate();
			pstackTable.repaint();

			for (int index = 0; index < calc.getB3_34memory().getSize(); index++) {
				if (strMem[index].matches("NAN")) {
					strMem[index] = "+0.";
					if (canEdit > 0)
						chkMem.get(index).setSelected(false);
				} else {
					if (canEdit > 0 && !unCheck) {
						chkMem.get(index).setSelected(true);
					} else {
						chkMem.get(index).setSelected(false);
					}
				}
				txtMem.get(index).setText(strMem[index]);
			}

		} catch (Exception ex) {
			System.out
					.println("CRegistreForm: registreUpdate: Error during registre update \n"
							+ ex.getMessage());
		}
	}

	public boolean isNumericDouble(String str) {
		try {
			@SuppressWarnings("unused")
			double d = Double.parseDouble(str);
		} catch (NumberFormatException nfe) {
			return false;
		}
		return true;
	}

	public boolean isNumericInteger(String str) {
		try {
			@SuppressWarnings("unused")
			double d = Integer.parseInt(str);
		} catch (NumberFormatException nfe) {
			return false;
		}
		return true;
	}

	public class stackTableModel implements TableModel {

		private Set<TableModelListener> listeners = new HashSet<TableModelListener>();

		private List<stackBean> stackBeans;

		public stackTableModel(List<stackBean> stackBeans) {
			this.stackBeans = stackBeans;
		}

		public void addTableModelListener1(TableModelListener listener) {
			listeners.add(listener);
		}

		public Class<?> getColumnClass(int columnIndex) {
			if (columnIndex == 2)
				return Boolean.class;
			return String.class;
		}

		public int getColumnCount() {
			return 3;
		}

		public String getColumnName(int columnIndex) {
			switch (columnIndex) {
			case 0:
				return CEnvironment.RegistreStackTableHeader0;
			case 1:
				return CEnvironment.RegistreStackTableHeader1;
			case 2:
				return CEnvironment.RegistreStackTableHeader2;
			}
			return "";
		}

		synchronized public int getRowCount() {
			return stackBeans.size();
		}

		synchronized public Object getValueAt(int rowIndex, int columnIndex) {
			stackBean bean = stackBeans.get(rowIndex);
			switch (columnIndex) {
			case 0:
				return bean.getCount();
			case 1:
				return bean.getValue();
			case 2:
				return bean.getCheck();
			}
			return "";
		}

		public boolean isCellEditable(int rowIndex, int columnIndex) {

			if (canEdit == 0)
				return false;
			if (columnIndex == 1 || columnIndex == 2)
				return true;

			return false;
		}

		public void removeTableModelListener1(TableModelListener listener) {
			listeners.remove(listener);
		}

		public void setValueAt(Object value, int rowIndex, int columnIndex) {
			if (columnIndex == 2)
				this.stackBeans.get(rowIndex).setCheck((Boolean) value);
			else if (isNumericDouble((String) value))
				this.stackBeans.get(rowIndex).setValue((String) value);
		}

		@Override
		public void addTableModelListener(TableModelListener l) {
		}

		@Override
		public void removeTableModelListener(TableModelListener l) {
		}

	}

	public class pstackTableModel implements TableModel {

		private Set<TableModelListener> listeners = new HashSet<TableModelListener>();

		private List<stackBean> stackBeans;

		public pstackTableModel(List<stackBean> stackBeans) {
			this.stackBeans = stackBeans;
		}

		public void addTableModelListener1(TableModelListener listener) {
			listeners.add(listener);
		}

		public Class<?> getColumnClass(int columnIndex) {
			if (columnIndex == 2)
				return Boolean.class;
			return String.class;
		}

		public int getColumnCount() {
			return 3;
		}

		public String getColumnName(int columnIndex) {
			switch (columnIndex) {
			case 0:
				return CEnvironment.RegistreStackTableHeader0;
			case 1:
				return CEnvironment.RegistreStackTableHeader1;
			case 2:
				return CEnvironment.RegistreStackTableHeader2;
			}
			return "";
		}

		synchronized public int getRowCount() {
			return stackBeans.size();
		}

		synchronized public Object getValueAt(int rowIndex, int columnIndex) {
			stackBean bean = stackBeans.get(rowIndex);
			switch (columnIndex) {
			case 0:
				return bean.getCount();
			case 1:
				return bean.getValue();
			case 2:
				return bean.getCheck();
			}
			return "";
		}

		public boolean isCellEditable(int rowIndex, int columnIndex) {

			if (canEdit == 0)
				return false;
			if (columnIndex == 1 || columnIndex == 2)
				return true;

			return false;
		}

		public void removeTableModelListener1(TableModelListener listener) {
			listeners.remove(listener);
		}

		public void setValueAt(Object value, int rowIndex, int columnIndex) {
			if (columnIndex == 2)
				this.stackBeans.get(rowIndex).setCheck((Boolean) value);
			else if (isNumericDouble((String) value))
				this.stackBeans.get(rowIndex).setValue((String) value);
		}

		@Override
		public void addTableModelListener(TableModelListener l) {
		}

		@Override
		public void removeTableModelListener(TableModelListener l) {
		}

	}

	public class stackBean {

		private String count;
		private String value;
		private boolean check;

		public stackBean(String count, String value, boolean check) {
			this.setCount(count);
			this.setValue(value);
			this.setCheck(check);
		}

		public void setCount(String c) {
			this.count = c;
		}

		public String getCount() {
			return count;
		}

		public void setValue(String v) {
			this.value = v;
		}

		public String getValue() {
			return value;
		}

		public void setCheck(boolean c) {
			this.check = c;
		}

		public boolean getCheck() {
			return check;
		}
	}

	public void setEditable(int index) {

		canEdit = index;
		if (index > 0) txtX0.setEditable(true);
		for (int i = 0; i < txtMem.size(); i++) {
			txtMem.get(i).setEditable(true);
			if (index == 2) 
				chkMem.get(i).setVisible(true);
		}

		registreUpdate();
	}

	protected void setRegisters() {

		double[] fStack0 = new double[stackBeans.size() + 1];
		int[] fStack1 = new int[pstackBeans.size()];
		double[] fMem = new double[txtMem.size()];

		try {

			for (int i = 0; i < txtMem.size(); i++)
				if (chkMem.get(i).isSelected())
					fMem[i] = Double
							.parseDouble(txtMem.get(i).getText().trim());
				else
					fMem[i] = Double.NaN;

			
			fStack0[0] = Double.parseDouble(txtX0.getText().trim());

			for (int i = 0; i < stackBeans.size(); i++)
				if (stackBeans.get(i).getCheck())
					fStack0[i + 1] = Double.parseDouble(stackBeans.get(i)
							.getValue().trim());
				else
					fStack0[i + 1] = Double.NaN;

			for (int i = 0; i < pstackBeans.size(); i++)
				if (pstackBeans.get(i).getCheck())
					fStack1[i] = Integer.parseInt(pstackBeans.get(i).getValue()
							.trim());
				else
					fStack1[i] = Integer.MAX_VALUE;

			calc.setB3_34memory(fMem);
			calc.setB3_34stack(fStack0);
			calc.setB3_34returnstack(fStack1);

		} catch (Exception ex) {
			System.out
					.println("CRegistreForm: setRegisters " + ex.getMessage());
		}

	}

	public void setUncheck(boolean b) {
		unCheck = b;
	}
}
